﻿#include "filewidget.h"
#include "ui_filewidget.h"
#include "filelistitem.h"
#include "clientdisktcpsocket.h"
#include <QInputDialog>
#include <QMessageBox>
#include <QFileInfo>
#include <QMimeDatabase>
#include <QMimeType>
#include "utils.h"
#include "threadfileio.h"
#include <QFileDialog>
#include <QThread>

FileWidget::FileWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::FileWidget)
{
    ui->setupUi(this);

    // 设置上方菜单样式widget样式
    ui->widget->setStyleSheet(

        "QWidget#widget{"
        "background-color:rgb(255,255,255);"
        "border:0px solid white;"
        "}"
        "QPushButton{"
        "border: 0px solid rgb(0,107,190);"
        " background-color: rgb(224,238,249);"
        "padding:8px;"
        "border-radius:8px;"
        "}"
        // "QPushButton:hover {"
        // "color: black;"
        // " }"
        "QPushButton:pressed {"
        "border: 0px solid rgb(0,84,154);"
        "background-color: rgb(204,228,247);"
        "color: black;"
        "}"

    );
    ui->widget_progressbar->setStyleSheet(
        "QWidget#widget_progressbar{"
        "background-color:rgb(255,255,255);"
        "border:0px solid white;"
        "}"
        );
    ui->progressBar->setStyleSheet(
        "QProgressBar{"
        "    font:9pt;"
        "    border-radius:5px;"
        "    text-align:center;"
        "    border:1px solid #E8EDF2;"
        "    background-color: rgb(255, 255, 255);"
        "    border-color: rgb(180, 180, 180);"
        "}"
        "QProgressBar:chunk{"
        "    border-radius:5px;"
        "    background-color:#1ABC9C;"
        "}"
        );
    QListWidgetItem* listItem;
    FileListItem* fileListItem;
    listItem = new QListWidgetItem(ui->listWidget);
    listItem->setSizeHint(QSize(100,60));
    fileListItem = new FileListItem;
    fileListItem->setFileName("文件名");
    fileListItem->setFileSize("文件大小(Kb)");
    fileListItem->setFIleType("文件类型");
    fileListItem->setFileImg("");
    fileListItem->setFileTime("修改时间");
    listItem->setFlags(Qt::NoItemFlags);
    ui->listWidget->setItemWidget(listItem,fileListItem);

    // // 设置右键菜单策略
    ui->listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
    // // 连接右键菜单信号
    connect(ui->listWidget, &QListWidget::customContextMenuRequested, this, &FileWidget::slot_showContextMenu);


    initProgressBar();
}

FileWidget::~FileWidget()
{
    delete ui;
}

QString FileWidget::getFileCategory(const QString &fileName)
{
    QMimeDatabase mimeDatabase;
    QMimeType mimeType = mimeDatabase.mimeTypeForFile(fileName);

    if (mimeType.name().startsWith("text/") ||
        mimeType.name().startsWith("application/vnd.ms-office") ||
        mimeType.name().startsWith("application/vnd.openxmlformats-officedocument") ||
        mimeType.name().startsWith("application/x-wps-office")) {

        return FILE_TYPE_TEXT;
    } else if (mimeType.name().startsWith("video/")) {
        return FILE_TYPE_VIDEO;
    } else if (mimeType.name().startsWith("audio/")) {
        return FILE_TYPE_MUSIC;
    }else if (mimeType.name().startsWith("image/")) {
        return FILE_TYPE_IMAGE;
    } else if (mimeType.name().startsWith("application/zip") ||
               mimeType.name().startsWith("application/x-rar") ||
               mimeType.name().startsWith("application/x-7z-compressed") ||
               mimeType.name().startsWith("application/x-tar") ||
               mimeType.name().startsWith("application/gzip")) {
        return FILE_TYPE_ZIP;
    }else {
        return FILE_TYPE_UNKNOW;
    }
}

void FileWidget::flushFiles()
{
    // 刷新所有文件
    QString strCurPath = ClientDiskTcpSocket::getInstance()->curPath();
    PDU *pdu = mkPDU(strCurPath.toUtf8().size() + 1);
    pdu->uiMsgType = ENUM_MSG_TYPE_FLUSH_DIR_REQUEST;
    memcpy(pdu->csMsg, strCurPath.toStdString().c_str(),strCurPath.toUtf8().size());
    ClientDiskTcpSocket::getInstance()->write((char *)pdu, pdu->uiPDULen);
    free(pdu);
    pdu = NULL;
}

void FileWidget::handleCreateDirRespond(PDU* pdu)
{
    QMessageBox::information(this,"创建文件",pdu->caData);
    flushFiles();
}

void FileWidget::handleUpdateFileList(const PDU *pdu)
{
    if(NULL == pdu)
    {
        return;
    }
    QListWidgetItem *listItem = NULL;
    FileListItem* fileListItem = NULL;
    int row = ui->listWidget->count();
    while(ui->listWidget->count() > 1)
    {
        listItem = ui->listWidget->item(row - 1);
        fileListItem = (FileListItem*)ui->listWidget->itemWidget(listItem);
        ui->listWidget->removeItemWidget(listItem);
        delete fileListItem;
        delete listItem;
        row -= 1;
    }
    FileInfo *pFileInfo = NULL;
    int iCount = pdu->uiMsgLen / sizeof(FileInfo);
    for(int i = 0;i<iCount;i++)
    {
        listItem = new QListWidgetItem(ui->listWidget);
        pFileInfo = (FileInfo*)(pdu->csMsg) + i;
        fileListItem = new FileListItem;

        QString fileName = pFileInfo->caName;
        if(0 == pFileInfo->bIsDir)
        {
            fileListItem->setFIleType(FILE_TYPE_FOLDER);
        }
        else{
            QString fileType = getFileCategory(fileName);
            fileListItem->setFIleType(fileType);
        }
        fileListItem->setFileName(fileName);
        fileListItem->setFileSize(QString::number(pFileInfo->uiSize / 1024)+1);
        fileListItem->setFileTime(pFileInfo->caTime);

        listItem->setSizeHint(QSize(100,60));
        ui->listWidget->setItemWidget(listItem,fileListItem);
    }
}

void FileWidget::handleDeleteFileRespond(const PDU *pdu)
{
    flushFiles();
    MYLOG<<"文件删除结果："<<pdu->caData;
}

void FileWidget::handleRenameFile(const PDU *pdu)
{
    QMessageBox::information(this,"重命名",pdu->caData);
    flushFiles();
}

void FileWidget::handleEnterDir(const PDU *pdu)
{
    if(strcmp(pdu->caData,ENTRY_DIR_OK) == 0){
        // 进入文件夹成功
        char* newCurPath = new char[pdu->uiMsgLen];
        memcpy(newCurPath,pdu->csMsg,pdu->uiMsgLen);
        MYLOG<<"当前路径："<<newCurPath<<" "<<pdu->uiMsgLen;
        ClientDiskTcpSocket::getInstance()->setStrCurPath(newCurPath);
        flushFiles();

    }else if(strcmp(pdu->caData, ENTRY_DIR_FAILED) == 0){
        // 进入文件夹失败
        QMessageBox::information(this,"失败",QString(ENTRY_DIR_FAILED));
    }
}

void FileWidget::handleUploadFile(PDU* pdu)
{
    if(strcmp(pdu->caData,UPLOAD_FILE_FAILED)== 0){
        QMessageBox::information(this, "失败","文件上传失败!"+QString(UPLOAD_FILE_FAILED));
        return;
    }

    QFile file(m_strUploadFilePath);
    if (!file.open(QIODevice::ReadOnly)) {
        MYLOG<<"打开文件失败";
        return;
    }
    int maxLenth = 4096;
    char* buffer = new char[maxLenth];
    qint64 bytesRead = 0;
    QTimer time;
    qint64 fileSize = file.size();
    qint64 hasSendSize = 0;
    ui->progressBar->setRange(hasSendSize,fileSize);
    ui->progressBar->setValue(hasSendSize);
    while ((bytesRead = file.read(buffer, maxLenth)) > 0) {
        PDU* pduData = mkPDU(bytesRead);
        pduData->uiMsgType = ENUM_MSG_TYPE_UPLOADING_FILE_REQUEST;
        memcpy(pduData->csMsg,buffer,bytesRead);
        ClientDiskTcpSocket::getInstance()->write((char* )pduData,pduData->uiPDULen);
        // MYLOG<<"size:"<<bytesRead<<" "<<pduData->uiMsgLen;
        free(pduData);
        pduData = NULL;
        ClientDiskTcpSocket::getInstance()->waitForBytesWritten();
        hasSendSize += bytesRead;
        ui->progressBar->setValue(hasSendSize);
    }
    file.close();
}

void FileWidget::handleUploadedFile(PDU *pdu)
{
    QMessageBox::information(this, "上传",pdu->caData);
    if(strcmp(pdu->caData,UPLOAD_FILE_OK) == 0)
        flushFiles();
}

void FileWidget::initProgressBar()
{
    ui->progressBar->setFormat("%v bytes:%m bytes -- %p%");
    ui->progressBar->setValue(0);
}

void FileWidget::on_pbn_newFlloder_clicked()
{
    bool ok;
    QString strNewDir = QInputDialog::getText(this,"新建文件夹","新文件夹名字",
                                              QLineEdit::Normal,"",&ok,Qt::MSWindowsFixedSizeDialogHint);
    if(!strNewDir.isEmpty())
    {
        if(strNewDir.toUtf8().size() > 32)
        {
            QMessageBox::warning(this,"新建文件夹","新文件夹名字过长！");
        }
        else
        {
            QString strName = ClientDiskTcpSocket::getInstance()->usrName();
            QString strCurPath = ClientDiskTcpSocket::getInstance()->curPath();
            PDU *pdu = mkPDU(strCurPath.toUtf8().size() + 1);
            pdu->uiMsgType = ENUM_MSG_TYPE_CREATE_DIR_REQUEST;
            // 拷贝 用户名
            memcpy(pdu->caData,strName.toStdString().c_str(),32);
            // 拷贝 新建文件夹名
            memcpy(pdu->caData+32,strNewDir.toStdString().c_str(),32);
            // 拷贝 当前路径
            memcpy(pdu->csMsg,strCurPath.toStdString().c_str(),strCurPath.size());
            ClientDiskTcpSocket::getInstance()->write((char*)pdu,pdu->uiPDULen);
            free(pdu);
            pdu = NULL;
        }
    }
    else
    {
        QMessageBox::warning(this,"新建文件夹","新文件夹名字不能为空");
    }
}


void FileWidget::on_pbn_flush_clicked()
{
    flushFiles();
}

void FileWidget::slot_showContextMenu(const QPoint& pos)
{
    contextMenu = new QMenu();

    actionDelete = new QAction(tr("删除"), contextMenu);
    connect(actionDelete, &QAction::triggered, this, &FileWidget::slot_deleteFile);
    actionRename = new QAction(tr("重命名"), contextMenu);
    connect(actionRename, &QAction::triggered, this, &FileWidget::slot_renameFile);
    actionDownload = new QAction(tr("下载"), contextMenu);
    connect(actionDownload, &QAction::triggered, this, &FileWidget::slot_downloadFile);


    contextMenu->addAction(actionDelete);
    contextMenu->addAction(actionRename);
    contextMenu->addSeparator();
    contextMenu->addAction(actionDownload);



    // 设置菜单样式
    contextMenu->setStyleSheet(
        "QMenu {"
        "    color: black;"
        "    background-color: white;"
        "    border-radius: 10px;"
        "    padding: 5px;"
        "    margin: 2px;"
        "}"
        "QMenu::item {"
        "    border-radius: 20px;"
        "}"
        "QMenu::item:text {"
        "    padding-top: 8px;"
        "    padding-bottom: 8px;"
        "    padding-left: 30px;"
        "    padding-right: 30px;"
        "}"
        "QMenu::item:selected {"
        "    color: #1aa3ff;"
        "    background-color: #e5f5ff;"
        "    border-radius: 8px;"
        "}"
        "QMenu::separator {"
        "    height: 1px;"
        "    background: #bbbbbb;"
        "    margin: 5px;"
        "    margin-left: 10px;"
        "    margin-right: 10px;"
        "}"
        );
    // contextMenu->setWindowFlags(contextMenu->windowFlags()  | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint);
    // contextMenu->setAttribute(Qt::WA_TranslucentBackground,true);
    // QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(contextMenu);
    // shadow->setOffset(0, 0);
    // shadow->setColor(QColor("#444444"));
    // shadow->setBlurRadius(10);
    // contextMenu->setGraphicsEffect(shadow);

    contextMenu->exec(ui->listWidget->mapToGlobal(pos));
    delete actionDelete;
    delete actionRename;
    delete contextMenu;
}

void FileWidget::slot_deleteFile()
{
    QString strCurPath = ClientDiskTcpSocket::getInstance()->curPath();
    QListWidgetItem *pItem = ui->listWidget->currentItem();
    FileListItem* pFileListItem = (FileListItem*)ui->listWidget->itemWidget(pItem);
    QString strDelName = pFileListItem->getFileName();

    PDU *pdu = mkPDU(strCurPath.toUtf8().size() + 1);
    pdu->uiMsgType = ENUM_MSG_TYPE_DELETE_FILE_REQUEST;
    strncpy_s(pdu->caData, strDelName.toStdString().c_str(), strDelName.toUtf8().size());
    memcpy(pdu->csMsg, strCurPath.toStdString().c_str(), strCurPath.toUtf8().size());
    ClientDiskTcpSocket::getInstance()->write((char *)pdu, pdu->uiPDULen);
    free(pdu);
    pdu = NULL;
}

void FileWidget::slot_renameFile()
{
    // 重命名文件
    QString strCurPath = ClientDiskTcpSocket::getInstance()->curPath();
    QListWidgetItem *pItem = ui->listWidget->currentItem();
    if (NULL == pItem) {
        QMessageBox::warning(this, "重命名文件", "请选择要重命名的文件");
    } else {
        FileListItem* pFileListItem = (FileListItem*)ui->listWidget->itemWidget(pItem);
        QString strOldName = pFileListItem->getFileName();
        bool ok;
        QString strNewName =
            QInputDialog::getText(this, "重命名文件", "请输入新的文件名",QLineEdit::Normal,"",&ok,Qt::MSWindowsFixedSizeDialogHint);
        if (!strNewName.isEmpty()) {
            std::string stdStrCurPath = strCurPath.toStdString();
            std::string stdStrOldName = strOldName.toStdString();
            std::string stdStrNewName = strNewName.toStdString();
            MYLOG<<"当前路径"<<strCurPath<<"的长度:"<<stdStrCurPath.size()<<"旧名"<<strOldName<<"字节数："<<stdStrOldName.size()<<"新名"<<strNewName<<"字节数："<<stdStrNewName.size();
            PDU *pdu = mkPDU(stdStrCurPath.size() + 1);
            pdu->uiMsgType = ENUM_MSG_TYPE_RENAME_FILE_REQUEST;
            memcpy(pdu->caData, stdStrOldName.c_str(), strOldName.size());
            memcpy(pdu->caData + 32, stdStrNewName.c_str(),
                    stdStrNewName.size());
            memcpy(pdu->csMsg, stdStrCurPath.c_str(), stdStrCurPath.size());
            ClientDiskTcpSocket::getInstance()->write((char *)pdu, pdu->uiPDULen);
            free(pdu);
            pdu = NULL;
        } else {
            QMessageBox::warning(this, "重命名文件", "新文件名不能为空");
        }
    }
}

void FileWidget::slot_downloadFile()
{
    QListWidgetItem *pItem = ui->listWidget->currentItem();
    FileListItem* filelistitem = (FileListItem*)ui->listWidget->itemWidget(pItem);
    if(filelistitem->getFileType() == FILE_TYPE_FOLDER){
        slot_showDownloadStatus("文件夹暂不支持下载！");
        return;
    }
    m_strDownloadDirPath = QFileDialog::getExistingDirectory(this,"文件下载","../");
    if (!m_strDownloadDirPath.isEmpty()) {
        QString strFileName = filelistitem->getFileName();
        QString strCurPath = ClientDiskTcpSocket::getInstance()->curPath();
        QString remotePath = strCurPath +"/"+strFileName;
        QString localPath = m_strDownloadDirPath + "/" + strFileName;
        ui->lb_fileName->setText(strFileName);
        ui->lb_Status->setText("文件下载：");
        ThreadFileIO *m_threadFileIO =
            new ThreadFileIO(remotePath, localPath, "127.0.0.1", 8888,
                             ENUM_THREAD_TYPE_DOWNLOAD_FILE);
        QThread* thread = new QThread();
        m_threadFileIO->moveToThread(thread);
        connect(thread,&QThread::started,m_threadFileIO,&ThreadFileIO::slot_connectToHost);
        connect(m_threadFileIO,&ThreadFileIO::signal_setProgeressBarMaxValue,this,&FileWidget::slot_setProgressBarMaxValue);
        connect(m_threadFileIO,&ThreadFileIO::signal_setProgeressBarValue,this,&FileWidget::slot_setProgressBarValue);
        connect(m_threadFileIO,&ThreadFileIO::signal_DownloadFileStatus,this,&FileWidget::slot_showUploadStatus);

        // 确保线程正确退出和清理
        // 线程完成后清理
        connect(thread, &QThread::finished, thread, &QThread::deleteLater);
        connect(thread, &QThread::finished, m_threadFileIO, &ThreadFileIO::deleteLater);
        connect(m_threadFileIO, &ThreadFileIO::destroyed, thread, &QThread::quit);
        thread->start();
        //../1/压力系数数据.zip
        //79581b163ecf3e80dc23ee3e85c4e2c5

    }
}

void FileWidget::on_listWidget_itemDoubleClicked(QListWidgetItem *item)
{
    FileListItem* m_pFileListItem = (FileListItem*)ui->listWidget->itemWidget(item);

    QString strDirName = m_pFileListItem->getFileName();
    QString strCurPath = ClientDiskTcpSocket::getInstance()->curPath();

    PDU *pdu = mkPDU(strCurPath.toStdString().size() + 1);
    pdu->uiMsgType = ENUM_MSG_TYPE_ENTRY_DIR_REQUEST;
    strcpy_s(pdu->caData,strDirName.toStdString().c_str());
    memcpy(pdu->csMsg,strCurPath.toStdString().c_str(),strCurPath.toStdString().size());
    ClientDiskTcpSocket::getInstance()->write((char*)pdu,pdu->uiPDULen);
    free(pdu);
    pdu = NULL;
}

void FileWidget::on_pbn_back_clicked()
{

    QString strDirName = "..";
    QString strCurPath = ClientDiskTcpSocket::getInstance()->curPath();

    PDU *pdu = mkPDU(strCurPath.toStdString().size() + 1);
    pdu->uiMsgType = ENUM_MSG_TYPE_ENTRY_DIR_REQUEST;
    strcpy_s(pdu->caData,strDirName.toStdString().c_str());
    memcpy(pdu->csMsg,strCurPath.toStdString().c_str(),strCurPath.toStdString().size());
    ClientDiskTcpSocket::getInstance()->write((char*)pdu,pdu->uiPDULen);
    free(pdu);
    pdu = NULL;
}

void FileWidget::on_pbn_upload_clicked()
{
    m_strUploadFilePath = QFileDialog::getOpenFileName(nullptr,"上传文件","../");
    if (!m_strUploadFilePath.isEmpty()) {
        int index = m_strUploadFilePath.lastIndexOf('/');
        QString strFileName =
            m_strUploadFilePath.right(m_strUploadFilePath.size() - index - 1);
        QString strCurPath = ClientDiskTcpSocket::getInstance()->curPath();
        QString remotePath = strCurPath +"/"+strFileName;
        ui->lb_fileName->setText(strFileName);
        ui->lb_Status->setText("文件上传：");
        ThreadFileIO *m_threadFileIO =
            new ThreadFileIO(remotePath, m_strUploadFilePath, "127.0.0.1", 8888,
                                                        ENUM_THREAD_TYPE_UPLOAD_FILE);
        QThread* thread = new QThread();
        m_threadFileIO->moveToThread(thread);
        connect(thread,&QThread::started,m_threadFileIO,&ThreadFileIO::slot_connectToHost);
        connect(m_threadFileIO,&ThreadFileIO::signal_setProgeressBarMaxValue,this,&FileWidget::slot_setProgressBarMaxValue);
        connect(m_threadFileIO,&ThreadFileIO::signal_setProgeressBarValue,this,&FileWidget::slot_setProgressBarValue);
        connect(m_threadFileIO,&ThreadFileIO::signal_UploadFileStatus,this,&FileWidget::slot_showUploadStatus);

        // 确保线程正确退出和清理
        // 线程完成后清理
        connect(thread,&QThread::finished,[](){
            MYLOG<<"线程结束！";
        });
        connect(thread, &QThread::finished, thread, &QThread::deleteLater);
        connect(thread, &QThread::finished, m_threadFileIO, &ThreadFileIO::deleteLater);
        connect(m_threadFileIO, &ThreadFileIO::destroyed, thread, &QThread::quit);

        thread->start();
    }
}

void FileWidget::slot_setProgressBarMaxValue(qint64 value)
{
    MYLOG<<value;
    ui->progressBar->setRange(0 , value);
}

void FileWidget::slot_setProgressBarValue(qint64 value)
{
    // MYLOG<<value;
    ui->progressBar->setValue(value);
}

void FileWidget::slot_showUploadStatus(QString status)
{
    QMessageBox::information(this, "上传文件",status);
    flushFiles();
}

void FileWidget::slot_showDownloadStatus(QString status)
{
    QMessageBox::information(this, "文件下载",status);
}

